using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;

using SchemaProvider;

namespace Kenly.DBFramework.ORMCodeHelper
{
    public static class PluginManager
    {

        #region Public

        /// <summary>
        /// 
        /// </summary>
        /// <param name="pluginDir"></param>
        /// <returns></returns>
        public static List<string> GetSchemaProviderPluginNames(string pluginDir)
        {
            List<string> schemaProviderPluginNames = new List<string>();
            if (!Directory.Exists(pluginDir))
            {
                return schemaProviderPluginNames;
            }
            string[] fileNames = Directory.GetFiles(pluginDir);
            if (fileNames.Length <= 0)
            {
                return schemaProviderPluginNames;
            }
            foreach (string fileName in fileNames)
            {
                if (IsSchemaProviderPlugin(fileName))
                {
                    FileInfo fileInfo = new FileInfo(fileName);
                    schemaProviderPluginNames.Add(fileInfo.Name);
                }
            }
            return schemaProviderPluginNames;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="schemaLoader"></param>
        /// <param name="codeProvider"></param>
        public static void LoadSchemaProviderPlugin(string filePath, out ISchemaLoader schemaLoader,
            out IProcedureCodeProvider procedureCodeProvider, out ITableCodeProvider tableCodeProvider, out IViewCodeProvider viewCodeProvider)
        {
            schemaLoader = null;
            procedureCodeProvider = null;
            tableCodeProvider = null;
            viewCodeProvider = null;
            Type[] types = Assembly.LoadFile(filePath).GetTypes();
            foreach (Type type in types)
            {
                if (type.IsAbstract)
                {
                    continue;
                }

                Type[] interfaceTypes = type.GetInterfaces();
                foreach (Type interfaceType in interfaceTypes)
                {
                    if (interfaceType == typeof(ISchemaLoader))
                    {
                        schemaLoader = Activator.CreateInstance(type) as ISchemaLoader;
                        break;
                    }
                    if (interfaceType == typeof(IProcedureCodeProvider))
                    {
                        procedureCodeProvider = Activator.CreateInstance(type) as IProcedureCodeProvider;
                        break;
                    }
                    if (interfaceType == typeof(ITableCodeProvider))
                    {
                        tableCodeProvider = Activator.CreateInstance(type) as ITableCodeProvider;
                        break;
                    }
                    if (interfaceType == typeof(IViewCodeProvider))
                    {
                        viewCodeProvider = Activator.CreateInstance(type) as IViewCodeProvider;
                        break;
                    }
                }
            }

        }


        #endregion //Public



        #region Private

        /// <summary>
        /// 
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        private static bool IsSchemaProviderPlugin(string filePath)
        {
            Type[] types = Assembly.LoadFile(filePath).GetTypes();
            foreach (Type type in types)
            {
                if (!type.IsAbstract && ImplementSchemaProviderInterface(type))
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private static bool ImplementSchemaProviderInterface(Type type)
        {
            Type[] interfaceTypes = type.GetInterfaces();
            foreach (Type interfaceType in interfaceTypes)
            {
                if (interfaceType == typeof(ISchemaLoader) || interfaceType == typeof(ICodeProvider))
                {
                    return true;
                }
            }
            return false;
        } 

        #endregion //Private


    }
}
